#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
typedef uint64_t u64;
typedef uint8_t u8;
typedef int64_t i64;


#define _PRINT 0


typedef u64 iofunc( void* data, u64 start, u64 l, FILE* stream);

void add_cas(volatile u64* v0,u64 v1){
    u64 except_value = *v0+v1;
    *v0 =except_value;
    while(*v0!=except_value){
        except_value = *v0+v1;
        *v0 =except_value;
    }
}
u64 my_read( void* data, u64 start, u64 l, FILE* stream){
    int seek_rs = fseek(stream, start, SEEK_SET);
    if (seek_rs ==0){
        #if _PRINT
            printf("seek success, except seek to %llu, now at %lld\n", start, ftell(stream));
        #endif
        return (u64)fread(data, 1, l, stream);
    }else{
        #if _PRINT
            printf("seek fault, except seek to %llu, now at %lld\n", start, ftell(stream));
        #endif
        return 0;
    }
}
u64 my_write( void* data, u64 start, u64 l, FILE* stream){
    int seek_rs = fseek(stream, start, SEEK_SET);
    if (seek_rs ==0){
        #if _PRINT
            printf("seek success, except seek to %llu, now at %llu\n", start, ftell(stream));
        #endif
        return (u64)fwrite(data, 1, l, stream);
    }else{
        #if _PRINT
            printf("seek fault, except seek to %llu, now at %lld\n", start, ftell(stream));
        #endif
        return 0;
    }
}

typedef struct{
    char* ptr;
    u64 start, l ;
    FILE* stream;
    volatile u64* success_bytes;

} iotask;

u64 get_time_ms(){
    clock_t t0=clock();
    return (u64)( 1000*(t0/CLOCKS_PER_SEC) );
}

typedef struct{
    iotask* free_ptr;
    volatile iotask* iotask_vptr;
    u64 read_iotask_l, write_iotask_l;
    u8 stat_in, stat_out, error_code;
    u64 latest_dida_time_ms, auto_yield_time_ms, auto_sleep_time_ms;
    u64 remain_bytes, next_i;
    void* thread_handle;
} ioThreadArgs;


#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(WIN32)
    #include <windows.h>
    #include <processthreadsapi.h>
    #include<process.h>
    #include<io.h>
    inline void fsync_stream(FILE* stream){
        int fd = _fileno(stream);
        _commit(fd);
    }
    inline void fsync_fd(int fd){
        _commit(fd);
    }
    inline void my_thread_yield(){
        SwitchToThread();
    }
    inline void my_thread_sleep(){
        Sleep(0);
    }

#elif defined(_POSIX_VERSION)
    #include<pthread.h>
    #include<unistd.h>
    inline void fsync_stream(FILE* stream){
        int fd = _fileno(stream);
        _commit(fd);
    }
    inline void fsync_fd(int fd){
        fsync(fd);
    }
    inline void my_thread_yield(){
        pthread_yield();
    }
    inline void my_thread_sleep(){
        sleep(0);
    }

#endif


#define READ 0
#define WRITE READ+1
#define YIELD WRITE+1
#define SLEEP YIELD+1
#define EXIT SLEEP+1
#define EXITED EXIT+1
#define PREPARE 255

inline void dida(volatile ioThreadArgs* io_thread_args_vptr,char stat_out){
    io_thread_args_vptr->latest_dida_time_ms = get_time_ms();
    io_thread_args_vptr->stat_out = stat_out;
}


inline void do_work(volatile ioThreadArgs* io_thread_args_vptr,volatile iotask* iotask_vptr,u64 iotask_l, iofunc* iofunc_ptr,volatile u64* remain_bytes_vptr,volatile u64* next_i,char stat_out){
    dida(io_thread_args_vptr, stat_out);
    iotask io_task;
    u64 i, l=iotask_l, read_size, remain_bytes = *remain_bytes_vptr;
    iotask_vptr;
    #if _PRINT
       char io_func = (iofunc_ptr==&my_read)? 'r':'w';
       printf("do work iotask,count=%llu,mode=%c\n" , l, io_func );
    #endif
    if (l > 0 && iotask_vptr!=NULL ){
        #if _PRINT
            printf("start work iotasks,count=%llu,mode=%c, thread_id: %p\n ", l, io_func, io_thread_args_vptr->thread_handle);
        #endif
        for (i=0;i<l;i++){
            io_task = *iotask_vptr;
            #if _PRINT
                printf("io iotasks[%llu] at time:%llu ms, start=%llu, len=%llu, ptr=%p, FILE=%p,  thread_id: %p\n ", i, get_time_ms(), io_task.start, io_task.end, io_task.ptr, io_task.stream, io_thread_args_vptr->thread_handle);
            #endif
            *next_i = i+1;
            iotask_vptr->start_time = get_time_ms();
            read_size = *io_func(io_task.ptr, io_task.start, io_task.l, io_task.stream);
            *(iotask_vptr->success_bytes) = read_size;
            #if _PRINT
                    printf("set success bytes to iotasks[%llu], address at %p, success_bytes: %llu,  io_task.l=%llu, thread_id: %p\n ", i, iotask.ptr, end_seek-start_seek, io_task.l, io_thread_args_vptr->thread_handle);
                #endif
            /*if read_size == io_task.l{
                #if _PRINT
                    printf("set success bytes to iotasks[%llu], address at %p, success_bytes: %llu,  io_task.l=%llu, thread_id: %p\n ", i, iotask.ptr, end_seek-start_seek, io_task.l, io_thread_args_vptr->thread_handle);
                #endif
                add_cas(iotask_vptr->success_bytes, read_size);
                //iotask_vptr->success_bytes = read_size;
                //iotask_vptr+=1;
            }
            else{
                #if _PRINT
                    printf("set fault bytes to iotasks[%llu], address at %p, fault_bytes: %llu,  io_task.l=%llu, thread_id: %p\n ", i, iotask.ptr, end_seek-start_seek, io_task.l, io_thread_args_vptr->thread_handle);
                #endif
                add_cas(iotask_vptr->success_bytes, read_size);
            remain_bytes -= io_task.l;
            *remain_bytes_vptr = remain_bytes;
            }*/

        }

        io_thread_args_vptr->stat_in = PREPARE;
    }
}

void loop_listen_iotasks(volatile ioThreadArgs* io_thread_args_vptr) {
    u64 t0, t1;
    t0=get_time_ms();
    while (1) {
        if ( io_thread_args_vptr->stat_in == READ ) {
            #if _PRINT
                printf("Enter reading at time:%llu ms，iotasks_address:%p, iotask_count:%llu ",get_time_ms(),io_thread_args_vptr->iotask_vptr, io_thread_args_vptr->iotask_l);
            #endif
            do_work(io_thread_args_vptr,io_thread_args_vptr->iotask_vptr, io_thread_args_vptr->read_iotask_l, &my_read, &io_thread_args_vptr->remain_bytes, &io_thread_args_vptr->next_i,  READ);
            io_thread_args_vptr->read_iotask_l = 0;
            t0=get_time_ms();
        }
        else if (io_thread_args_vptr->stat_in == WRITE ) {
            #if _PRINT
                printf("Enter writing at time:%llu ms，iotasks_address:%p, iotask_count:%llu",get_time_ms(),io_thread_args_vptr->io_thread_args_vptr, io_thread_args_vptr->iotask_l);
            #endif
            do_work(io_thread_args_vptr, io_thread_args_vptr->iotask_vptr, io_thread_args_vptr->write_iotask_l, &my_write, &io_thread_args_vptr->remain_bytes, &io_thread_args_vptr->next_i, WRITE);

            io_thread_args_vptr->write_iotask_l = 0;
            t0=get_time_ms();
        }
        else if (io_thread_args_vptr->stat_in == YIELD) {
            t0=get_time_ms();
            while (io_thread_args_vptr->stat_in == YIELD ) {
                dida(io_thread_args_vptr, YIELD);
                my_thread_yield();
                t1=get_time_ms();
                if (t1-t0>io_thread_args_vptr->auto_sleep_time_ms){io_thread_args_vptr->stat_in = SLEEP;}
            }
            t0=get_time_ms();
        } else if (io_thread_args_vptr->stat_in == SLEEP) {
            t0=get_time_ms();
            while (io_thread_args_vptr->stat_in == SLEEP) {
                dida(io_thread_args_vptr, SLEEP);
                my_thread_sleep();
            }
            t0=get_time_ms();
        } else if (io_thread_args_vptr->stat_in == EXIT) {
            break;
        }
        //
        t1=get_time_ms();
        if (t1-t0 >= io_thread_args_vptr->auto_yield_time_ms){ io_thread_args_vptr->stat_in = YIELD;}
        else if (t1-t0>io_thread_args_vptr->auto_sleep_time_ms){io_thread_args_vptr->stat_in = SLEEP;}
        else{ dida(io_thread_args_vptr, PREPARE);}
    }
    io_thread_args_vptr->stat_out = EXITED;
}

#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(WIN32)
    typedef uintptr_t threadHandle;
    void __cdecl wrap_loop_listen( void* args ){
        volatile ioThreadArgs* io_thread_args_vptr= (volatile ioThreadArgs*)args;
        loop_listen_iotasks( io_thread_args_vptr );
    }
    int start_io_thread( volatile ioThreadArgs* args_){
        void* args= (void*)args_;
        void* os_thread_handle_ptr = malloc(sizeof(uintptr_t));
        uintptr_t os_thread_handle = _beginthread( &wrap_loop_listen, 4096, args );
        if (os_thread_handle !=1L) {
            *(uintptr_t*)os_thread_handle_ptr = os_thread_handle;
            args_->thread_handle = os_thread_handle_ptr;
            return 0;
        }else{ return -1; }

    }

#elif defined (_POSIX_VERSION)
    typedef pthread_t threadHandle;
    void* wrap_loop_listen( void* args ){
        volatile ioThreadArgs* io_thread_args_vptr= (volatile ioThreadArgs*)args;
        loop_listen_iotasks( io_thread_args_vptr );
        return NULL;
    }
    int start_io_thread( volatile ioThreadArgs* args_ ){
        void* args=(void* )args_;
        void* os_thread_handle_ptr = malloc(sizeof(pthread_t));
        int flag = pthread_create( os_thread_handle_ptr, NULL, &wrap_loop_listen, args );
        if flag ==0{
            *((uintptr_t*)os_thread_handle_ptr) = os_thread_handle;
            args_->thread_handle = os_thread_handle;
            return 0;
        }else{ return -1; }

    }
#endif

int main() {
    getchar();
}